#pragma once

#include <map>
#include <list>
#include "Vtlb.h"
#include "unknwn.h"

class CJoinPoint;
class CProceedingJoinPoint;
class IAdvice;

class CAspectorComObject
{
};

class IAspector
{
public:
	virtual void InstallAdvices(void* pObject,const type_info& type) = 0;
	void InstallAdvicesForCOM(IUnknown* pObject)
	{
		pObject->AddRef();
		InstallAdvices(pObject,typeid(CAspectorComObject));
	}
	template<class T> T* Create()
	{
		T* obj = new T();
		InstallAdvices(obj,typeid(T));
		return obj;
	}
};

typedef std::multimap<int, IAdvice* > CAdviceCollection;

class CAspector: public IAspector
{
	friend struct Vtlb;
	friend class CAdviceBase;
private:
	CAdviceCollection advices;
	std::map < CAspectorObject* , std::pair<type_info*, Vtlb* > > objects;
	static Vtlb aspectInstallerVtlb;
	static CAspector instance;
public:
	ASPECTOR_API static CAspector* Instance();
	void InstallAdvices(void* pObject,const type_info& type);
private:
	CAspector();
	void AddAdvice(IAdvice* advice);
	void RemoveAdvice(IAdvice* advice);
	int ExecuteAroundAdvices(CProceedingJoinPoint& joinPoint);
	void ExecuteBeforeAdvices(CJoinPoint& joinPoint);
	int ExecuteAfterAdvices(CJoinPoint& joinPoint,int returnValue);
	void ExecuteThrowAdvices(CJoinPoint& joinPoint);
public:
	int Invoke(CAspectorObject* pObject,int vtlbIndex,va_list stackParameters);
};
